﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Xml;

namespace RSSLibrary3
{
    [Serializable]
    public enum DownloadNewOn {NewGUID,NewFileName, Date, DoNotDowload};
    [Serializable]
    public class RSSFeed
    {
        private string _feedUrl = "";
        private bool _btvIntergration = false;
        private bool _removeItems = true;
        private DownloadNewOn _downloadOn = DownloadNewOn.NewGUID;
        private int _maxToDownload = -1;
        private string _saveTo = "";
        private string _title = "";
        private string _description = "";
        private List<RSSProperty> _rssProperties = new List<RSSProperty>();
        private string _link = "";
        private List<RSSItem> _rssItems = new List<RSSItem>();
        private DateTime _lastUpdated = new DateTime();
        public string exception = null;
        public RSSFeed()
        {

        }
        public RSSFeed(string feedUrl, bool BTVIntegration, bool removeItems, DownloadNewOn dno, int maxToDownload, string saveTo)
        {
            _feedUrl = feedUrl;
            _btvIntergration = BTVIntegration;
            _removeItems = removeItems;
            _downloadOn = dno;
            _maxToDownload = maxToDownload;
            _saveTo = saveTo;
            loadRssItems(false);
        }
        #region Methods to access Data
        public string feedURL
        {
            get { return _feedUrl; }
        }
        public string downloadOnFormated
        {
            get
            {
                if (_downloadOn == DownloadNewOn.DoNotDowload)
                    return "Do Not Download";
                else if (_downloadOn == DownloadNewOn.NewFileName)
                    return "New FileName";
                else if (_downloadOn == DownloadNewOn.NewGUID)
                    return "New GUID";
                else if (_downloadOn == DownloadNewOn.Date)
                    return "Date";
                else
                    return "";
            }

        }
        public bool btvIntergration
        {
            get { return _btvIntergration; }
        }
        public bool removeItems
        {
            get { return _removeItems; }
        }
        public DownloadNewOn downlaodOn
        {
            get { return _downloadOn; }
        }
        public int maxToDownload
        {
            get { return _maxToDownload; }
        }
        public string saveLocation
        {
            get { return _saveTo; }
        }
        public string title
        {
            get { return _title; }
        }
        public string description
        {
            get { return _description; }
        }
        public List<RSSProperty> rssProperties
        {
            get { return _rssProperties; }
        }
        public List<RSSItem> rssItems
        {
            get { return _rssItems; }
        }
        public string link
        {
            get { return _link; }
        }
        public DateTime lastUpdatedOn
        {
            get { return _lastUpdated; }
        }

        #endregion
        public void saveSetupChange(string feedUrl, bool BTVIntegration, bool removeItems, DownloadNewOn dno, int maxToDownload, string saveTo)
        {
            _feedUrl = feedUrl;
            _btvIntergration = BTVIntegration;
            _removeItems = removeItems;
            _downloadOn = dno;
            _maxToDownload = maxToDownload;
            _saveTo = saveTo;
            loadRssItems(false);
        }


        public List<RSSItem> loadRssItems(bool downloadItems)
        {
            try
            {
                
                searchDate = new DateTime();
                if (_rssItems.Count > 0)
                    searchDate = _rssItems[0].pubDate;
                for (int i = 1; i < _rssItems.Count; i++)
                {
                    if (_rssItems[i].pubDate > searchDate)
                    {
                        searchDate = _rssItems[i].pubDate;
                    }
                }
                if (searchDate.Equals(new DateTime()))
                {
                    searchDate = DateTime.MaxValue;
                }

                XmlDocument rssDoc = new XmlDocument();
                List<RSSItem> currentRssItems = new List<RSSItem>();
                List<RSSItem> toDownloadItems = new List<RSSItem>();
                XmlNode nodeRss = null;
                XmlNode nodeChannel = null;
                XmlNode nodeItem = null;
                int count = 0;
                WebRequest request = WebRequest.Create(_feedUrl);
                if (request is HttpWebRequest)
                {
                    ((HttpWebRequest)request).UserAgent = "BTV Podcatcher(" + System.Environment.OSVersion.VersionString + ")";
                    
                        
                }
                // Load the XML content into a XmlDocument
                WebResponse response = request.GetResponse();
                Stream stream = response.GetResponseStream();
                rssDoc.Load(stream);
                // Loop for the <rss> tag
                for (int i = 0; rssDoc != null && i < rssDoc.ChildNodes.Count; i++)
                {
                    // If it is the rss tag
                    if (rssDoc.ChildNodes[i].Name == "rss")
                    {
                        // <rss> tag found
                        nodeRss = rssDoc.ChildNodes[i];
                    }
                }
                // Loop for the <channel> tag
                for (int i = 0; nodeRss != null && i < nodeRss.ChildNodes.Count; i++)
                {
                    // If it is the channel tag
                    if (nodeRss.ChildNodes[i].Name == "channel")
                    {
                        // <channel> tag found
                        nodeChannel = nodeRss.ChildNodes[i];
                    }
                }
                if (nodeChannel != null)
                {
                    _rssProperties.Clear();
                }
                for (int i = 0; nodeChannel != null && i < nodeChannel.ChildNodes.Count; i++)
                {
                    if (nodeChannel.ChildNodes[i].Name == "title")
                    {
                        _title = nodeChannel.ChildNodes[i].InnerText;
                    }
                    else if (nodeChannel.ChildNodes[i].Name == "description")
                    {
                        _description = nodeChannel.ChildNodes[i].InnerText;
                    }
                    else if (nodeChannel.ChildNodes[i].Name == "link")
                    {
                        _link = nodeChannel.ChildNodes[i].InnerText;
                    }
                    else if (nodeChannel.ChildNodes[i].Name == "item")
                    {
                        //TODO Load the items
                        nodeItem = nodeChannel.ChildNodes[i];
                        string itemtitle = "";
                        string itemdescription = "";
                        DateTime itempubDate = new DateTime();
                        string itemdownloadURL = "";
                        string itemguid = "";
                        string itemlink = "";
                        List<RSSProperty> rssItemProperties = new List<RSSProperty>();

                        for (int j = 0; nodeItem != null && j < nodeItem.ChildNodes.Count; j++)
                        {
                            if (nodeItem.ChildNodes[j].Name == "title")
                            {
                                itemtitle = nodeItem.ChildNodes[j].InnerText;
                            }
                            else if (nodeItem.ChildNodes[j].Name == "description")
                            {
                                itemdescription = nodeItem.ChildNodes[j].InnerText;
                            }
                            else if (nodeItem.ChildNodes[j].Name == "link")
                            {
                                itemlink = nodeItem.ChildNodes[j].InnerText;
                            }
                            else if (nodeItem.ChildNodes[j].Name == "pubDate")
                            {
                                try
                                {
                                    if (!DateTime.TryParse(nodeItem.ChildNodes[j].InnerText, out itempubDate))
                                    {
                                        if (nodeItem.ChildNodes[j].InnerText.Length > 4)
                                        {

                                            if (!DateTime.TryParse(nodeItem.ChildNodes[j].InnerText.Substring(0, nodeItem.ChildNodes[j].InnerText.Length - 3), out itempubDate))
                                            {
                                                if (!DateTime.TryParse(nodeItem.ChildNodes[j].InnerText.Substring(4), out itempubDate))
                                                    if (nodeItem.ChildNodes[j].InnerText.Length > 7)
                                                    {

                                                        DateTime.TryParse(nodeItem.ChildNodes[j].InnerText.Substring(4, (nodeItem.ChildNodes[j].InnerText.Length) - 7), out itempubDate);
                                                    }
                                            }
                                        }
                                    }
                                }
                                catch (Exception)
                                {

                                }

                            }
                            else if (nodeItem.ChildNodes[j].Name == "enclosure")
                            {
                                try
                                {
                                    itemdownloadURL = nodeItem.ChildNodes[j].Attributes["url"].InnerText;
                                }
                                catch (Exception)
                                {
                                    //TODO Error URL not found
                                }
                            }
                            else if (nodeItem.ChildNodes[j].Name == "guid")
                            {
                                itemguid = nodeItem.ChildNodes[j].InnerText;
                            }
                            else
                            {
                                rssItemProperties.Add(new RSSProperty(nodeItem.ChildNodes[j].Name,nodeItem.ChildNodes[j].InnerText));
                            }
                            
                        }
                        RSSItem rssItem = new RSSItem(itemtitle, itemdescription, itempubDate, itemdownloadURL, itemguid, itemlink, this, rssItemProperties);
                        currentRssItems.Add(rssItem);
                        //rssItem.rssProperties.Count
                        //TODO CHECK to see if we need to download
                        if (downloadItems)
                        {
                            if (_downloadOn.Equals(DownloadNewOn.NewGUID))
                            {
                                searchCritera = rssItem.guid;
                                if (!(_rssItems.Exists(seachRssItemByGUID)))
                                {
                                    count++;
                                    if (_maxToDownload < 0 || count < _maxToDownload)
                                    {
                                        toDownloadItems.Add(rssItem);
                                    }
                                }
                                searchCritera = null;
                            }
                            else if (_downloadOn.Equals(DownloadNewOn.NewFileName))
                            {
                                searchCritera = rssItem.downloadURL;
                                if (!(_rssItems.Exists(seachRssItemByFileName)))
                                {
                                    count++;
                                    if (_maxToDownload < 0 || count < _maxToDownload)
                                    {
                                        toDownloadItems.Add(rssItem);
                                    }
                                }
                                searchCritera = null;
                            }
                            else if (_downloadOn.Equals(DownloadNewOn.Date))
                            {
                                if (rssItem.pubDate>searchDate)
                                {
                                    count++;
                                    if (_maxToDownload < 0 || count < _maxToDownload)
                                    {
                                        toDownloadItems.Add(rssItem);
                                    }
                                }
                            }
                        }
                        //if(_rssItems.Exists(
                    }
                    else
                    {
                        _rssProperties.Add(new RSSProperty(nodeChannel.ChildNodes[i].Name,nodeChannel.ChildNodes[i].InnerText));
                    }
                }
                if (this._removeItems)
                {
                    if (currentRssItems.Count > 0)
                        _rssItems = currentRssItems;
                    else
                    {
                        foreach (RSSItem rs in _rssItems)
                        {
                            rs.outdated = true;
                        }
                    }
                    
                }
                else
                {
                    foreach (RSSItem rs in _rssItems)
                    {
                        searchCritera = rs.guid;
                        if (!currentRssItems.Exists(seachRssItemByGUID))
                        {
                            rs.outdated = true;
                            currentRssItems.Add(rs);
                        }
                    }
                    _rssItems = currentRssItems;
                }
                searchDate = new DateTime();
                _lastUpdated = DateTime.Now;
                exception = null;
                return toDownloadItems;
            }
            catch (Exception e)
            {
                exception = e.ToString();
                _title = "Error with feed";
                _description = e.Message;
            }
            searchDate = new DateTime();
            return null;

            
        }
        private string searchCritera = null;
        private DateTime searchDate = new DateTime();
        private bool seachRssItemByGUID(RSSItem r)
        {
            return r.guid.Equals(searchCritera);
        }
        private bool seachRssItemByFileName(RSSItem r)
        {
            try
            {
                if ((r.downloadURL.Substring(r.downloadURL.LastIndexOf("/") + 1).Equals(searchCritera.Substring(searchCritera.LastIndexOf("/") + 1))))
                {

                    return true;
                }
            }
            catch (Exception)
            {

            }
            return false;

            
        }
        private bool searchRssItemByDate(RSSItem r)
        {
            if (r.pubDate > searchDate)
                return true;
            else
                return false;
        }
        private bool outdatedRssItem(RSSItem r)
        {
            return r.outdated;
        }
        public void removeOldItems()
        {
            _rssItems.RemoveAll(outdatedRssItem);
            
        }
    }



    [Serializable]
    public class RSSProperty
    {
        private string _Name = "";
        private string _Value = "";
        public RSSProperty(string name, string value)
        {
            _Name = name;
            _Value = value;
        }
        public string name
        {
            get { return _Name; }
        }
        public string value
        {
            get { return _Value; }
        }
    }

    [Serializable]
    public class RSSItem
    {
        private string _title = "";
        private string _description = "";
        private DateTime _pubDate = new DateTime();
        private string _downloadURL = "";
        private string _guid = "";
        private string _link = "";
        private RSSFeed _rssFeed = null;
        private List<RSSProperty> _rssItemProperties = new List<RSSProperty>();
        private DateTime _dateAdded = new DateTime();
        private bool _oldItem = false;
        public RSSItem(string title, string description, DateTime pubDate, string downloadURL, string guid, string link, RSSFeed rssFeed, List<RSSProperty> _rssItemProperties)
        {
            _title = title;
            _description = description;
            _pubDate = pubDate;
            _downloadURL = downloadURL;
            _guid = guid;
            _link = link;
            _rssFeed = rssFeed;
            this._rssItemProperties = _rssItemProperties;
            _dateAdded = DateTime.Now;

        }
        public bool outdated
        {
            get { return _oldItem; }
            set { _oldItem = value; }
        }
        public List<RSSProperty> rssProperties
        {
            get { return _rssItemProperties; }
        }
        public string guid
        {
            get { return _guid; }
        }
        public string downloadURL
        {
            get { return _downloadURL; }
        }
        public string title
        {
            get { return _title; }
        }
        public string description
        {
            get { return _description; }
        }
        public DateTime pubDate
        {
            get { return _pubDate; }
        }
        public RSSFeed rssFeed
        {
            get { return _rssFeed; }
        }
        public string link
        {
            get { return _link; }
        }
        public DateTime lastFoundOn
        {
            get { return _dateAdded; }
        }
    }
}
